use std::collections::HashMap;

use boa_engine::{
    js_string, object::ObjectInitializer, property::Attribute, Context, JsResult, JsValue, Source,
};
use boa_runtime::Console;
fn create_context() -> Context {
    let mut context = Context::default();
    let console = Console::init(&mut context);
    context
        .register_global_property(js_string!(Console::NAME), console, Attribute::all())
        .expect("the console object shouldn't exist yet");
    context
}

pub fn trigger() -> JsResult<()> {
    let js_code = r#"
      let a = {};
      let value = "hello 123 world".match(/\d+/);
      a.value = value;
      console.log(JSON.stringify(a, null, 2));
      a
  "#;

    // Instantiate the execution context
    let mut context = create_context();
    // Parse the source code
    let result = context.eval(Source::from_bytes(js_code))?;

    println!("{}", result.display());

    Ok(())
}

pub fn invoke_js_function() -> JsResult<()> {
    let mut context = create_context();
    // 1. 先定义JS函数
    context.eval(Source::from_bytes(
        r#"
            function myFunction(a, b, c, d) {
                console.log(a)
                d.key3 = "123";
                d.key4 = undefined;
                return a + " world " + b + c.key1 + d.key1;
            }
        "#,
    ))?;

    // 2. 获取JS函数对象 - 使用 js_string! 宏
    let my_function = context
        .global_object()
        .get(js_string!("myFunction"), &mut context)?;

    // 或者使用 PropertyKey::from
    // let my_function = context.global_object().get(PropertyKey::from("myFunction"), &mut context)?;

    // 3. 准备参数
    let arg1 = JsValue::from(js_string!("hello"));
    let arg2 = JsValue::from(42);

    let mut map: HashMap<String, i32> = HashMap::new();
    map.insert("key1".to_string(), 1);
    map.insert("key2".to_string(), 2);

    let json_value1 = serde_json::to_value(&map).unwrap();

    let arg3 = JsValue::from_json(&json_value1, &mut context)?;

    // let json_arg = json!({
    //     "key1": 1,
    //     "key2": 2
    // });

    // let arg4 = JsValue::from_json(&json_arg, &mut context)?;

    // 1. 创建可变的 JS 对象（替代原来的 arg4）
    let arg4 = ObjectInitializer::new(&mut context)
        .property(js_string!("key1"), 1, Attribute::all())
        .property(js_string!("key2"), 2, Attribute::all())
        .build();

    context.register_global_property(js_string!("myArg4"), arg4.clone(), Attribute::all())?;

    // 4. 调用函数
    if let Some(callable) = my_function.as_callable() {
        let result = callable.call(
            &JsValue::undefined(),
            &[arg1, arg2, arg3, arg4.into()],
            &mut context,
        )?;
        println!("{}", result.display());
    }

    // 获取并打印修改后的值
    let updated_value = context
        .global_object()
        .get(js_string!("myArg4"), &mut context)?;

    if let Some(updated_obj) = updated_value.as_object() {
        println!("通过全局变量获取:");

        // 方法1：使用 display()
        println!(
            "key1: {}",
            updated_obj.get(js_string!("key1"), &mut context)?.display()
        );
        println!(
            "key3: {}",
            updated_obj.get(js_string!("key3"), &mut context)?.display()
        );
    }

    let json_value = updated_value.to_json(&mut context)?;
    println!("完整JSON对象: {}", json_value);
    Ok(())
}
